#include <titanfall2/Player.h>
#include <sigscanner/ModuleScanner.h>
#include <format>
#include <stdexcept>
#include <titanfall2/UserCmd.h>


const static std::string clientEntityListSignature = "48 8D 0D ? ? ? ? E8 ? ? ? ? 48 8D 05 ? ? ? ? 48 8D 0D ? ? ? ? 0F 57 "
                                                     "C0 48 89 05 ? ? ? ? 48 8D 05 ? ? ? ? 45 33 C0";

[[nodiscard]]
uintptr_t GetEntityListPointer()
{
    const auto scanResult = signature_scanner::ModuleScanner("client.dll").FindPattern(clientEntityListSignature);

        if (!scanResult.has_value())
            throw std::runtime_error(std::format("Failed to find entity list! Pattern: '{}'",
                                                 clientEntityListSignature));

        const auto offsetToList = *(uint32_t*)(scanResult.value()+3);
        return scanResult.value()+offsetToList+7;
}

namespace titanfall2
{
    Player* Player::GetByIndex([[maybe_unused]] const size_t index)
    {
        static auto entityList = GetEntityListPointer();

        return *reinterpret_cast<Player**>(entityList + index * 0x20 + sizeof(uintptr_t));
    }

    int Player::Health() const
    {
        return GetByOffset<int>(0x390);
    }

    LifeState Player::LifeState() const
    {
        return GetByOffset<titanfall2::LifeState>(0x6C8);
    }

    Flags Player::Flags() const
    {
        return GetByOffset<titanfall2::Flags>(0x8C);
    }

    int Player::TeamNumber() const
    {
        return GetByOffset<int>(0x3A4);
    }

    int Player::MaxHealth() const
    {
        return GetByOffset<int>(0x4a8);
    }

    bool Player::Alive() const
    {
        return LifeState() == titanfall2::LifeState::ALIVE;
    }

    bool Player::InTitan() const
    {
        return GetByOffset<bool>(0x3EC);
    }
}